﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AMStudio.Common;
using System.Text.RegularExpressions;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using AMStudio.DelegateDispather;
using System.IO.Ports;
using System.Threading;

namespace AMStudio.Driver
{
    public class CognexScannerDriver : IAutomationDriver
    {
        private int intBeginRead = 0;
        protected ExceptionManager ExManager = EnterpriseLibraryContainer.Current.GetInstance<ExceptionManager>();

        private CognexDriverConfig myConfig = null;

        private DelegateDispather.IEventClient eventClient;
        public DelegateDispather.IEventClient EventClient
        {
            get { return eventClient; }
            set { eventClient = value; }
        }
        private CognexScanner hardwaredriver;
        private bool alreadyinitialized = false;
        private IExecuteReader result = new ExecuteReader(false);

        private String hardwareName = "CAMERA";
        public String HardwareName
        {
            get { return hardwareName; }
            set { hardwareName = value; }
        }
        private String hardwareEvent = "CAMERA_RET";
        public String HardwareEvent
        {
            get { return hardwareEvent; }
            set { hardwareEvent = value; }
        }

        public void Initialize(IEventManager eventManager, CognexDriverConfig config)
        {
            intBeginRead = 0;
            myConfig = config;
            hardwaredriver = new CognexScanner(config.IPAddress, config.TcpPort, config.User, config.Password);
            hardwaredriver.OnDataReceived += new CognexScanner.CameraDataReceivedHandler(hardwaredriver_OnDataReceived);
            hardwaredriver.OnConnectClosed += new CognexScanner.CameraConnectClosedHandler(hardwaredriver_OnConnectClosed);
            hardwaredriver.OnConnected += new CognexScanner.CameraConnectedHandler(hardwaredriver_OnConnected);
            eventClient = new EventClient(eventManager);
            this.hardwareEvent = config.HardwareEvent;
            this.hardwareName = config.HardwareName;
        }
        public virtual int ExecuteNonQuery(string command, params object[] parameters)
        {
            return -1;
        }
        public virtual IExecuteReader ExecuteReader(string command, params object[] parameters)
        {
//             intBeginRead = 0;
//             _Received_Data = null;
//             result.Success = false;
//             _Signal_Command_Finished.Reset();

            try
            {
                switch (command)
                {
                    case "INIT":
                        #region Command "INIT"
                        {
                            intBeginRead = 0;
                            _Received_Data = null;
                            result.Success = false;
                            _Signal_Command_Finished.Reset();

                            if (!alreadyinitialized)
                            {
                                this.Initialize((IEventManager)parameters[0], (CognexDriverConfig)parameters[1]);
                                if (!hardwaredriver.Initialize())
                                {
                                    Logger.Write("System Error! (Can not connect the laser controller!)");
                                    hardwaredriver.Close();
                                }
                                else
                                {
                                    result.Success=true;
                                    alreadyinitialized = true;                          
                                }
                            }
                        }
                        #endregion
                        break;
                    case "EXIT":
                        #region Command "DISCONNECT"
                        intBeginRead = 0;
                        _Received_Data = null;
                        result.Success = true;
                        _Signal_Command_Finished.Reset();

                        if (alreadyinitialized)
                        {
                            hardwaredriver.Close();
                            alreadyinitialized = false;
                        }
                        #endregion
                        break;
                    case "CONNECT_STATUS":
                        #region Command "CONNECT_STATUS"
                        {
                            if (alreadyinitialized)
                            {
                                result.Result = true;
                                result.Success = true;
                            }
                            else
                            {
                                result.Result = false;
                                result.Success = true;
                            }
                        }
                        #endregion
                        break;
                    case "TRIGGERON":
                        #region Command "TRIGGERON"
                        {
                            intBeginRead = 0;
                            _Received_Data = null;
                            result.Success = false;
                            _Signal_Command_Finished.Reset();

                            if (alreadyinitialized)
                            {
                                string str = string.Empty;
                                intBeginRead = Environment.TickCount & Int32.MaxValue;
                                result.Success = hardwaredriver.SendCommand("||>TRIGGER ON\r\n", string.Empty);
                            }
                        }
                        #endregion
                        break;
                    case "TRIGGEROFF":
                        #region Command "TRIGGEROFF"
                        {
                            intBeginRead = 0;
                            _Received_Data = null;
                            result.Success = false;
                            _Signal_Command_Finished.Reset();

                            if (alreadyinitialized)
                            {
                                string str = string.Empty;
                                result.Success = hardwaredriver.SendCommand("||>TRIGGER OFF\r\n", string.Empty);
                                intBeginRead = 0;
                            }
                        }
                        #endregion
                        break;
                    case "READ":
                        #region Command "READ"
                        {
                            if (alreadyinitialized)
                            {
                                if (_Signal_Command_Finished.WaitOne(1, false))
                                {
                                    result.Success = true;
                                    result.Result = _2DCode;
                                }
                                else
                                {
                                    int intTickCount = Environment.TickCount & Int32.MaxValue;
                                    int intTimeTaken = intTickCount < intBeginRead ? Int32.MaxValue - intBeginRead + intTickCount : intTickCount - intBeginRead;

                                    if (intTimeTaken > 3000)
                                    {
                                        RaiseEvent("TRIGGEROFF", true, null);
                                        result.Success = true;
                                        result.Result = "NOREAD";
                                    }
                                    else
                                    {
                                        result.Success = false;
                                    }
                                }
                            }
                        }
                        #endregion
                        break;
                    default:
                        break;
                }           
            }
            catch (Exception ex)
            {
                intBeginRead = 0;
                _Received_Data = null;
                result.Success = false;
                _Signal_Command_Finished.Reset();

                ExManager.HandleException(ex, "Policy");
                alreadyinitialized = false;
                RaiseEvent("DISCONNECT", true, null);
                if (hardwaredriver != null)
                    hardwaredriver.Close();
            }
            return result;
        }



        private void hardwaredriver_OnConnected(object sender, EventArgs e)
        {
            RaiseEvent("CONNECTED", true, null);
        }

        private void hardwaredriver_OnConnectClosed(object sender, EventArgs e)
        {
            alreadyinitialized = false;

            RaiseEvent("DISCONNECTED", true, null);
        }

        private void hardwaredriver_OnDataReceived(object sender, CameraArgs e)
        {
            _2DCode = e.ReceivedString;
            _Signal_Command_Finished.Set();
            RaiseEvent("DATA_RECEIVE", true, _2DCode);
        }


        #region Variable, common for each hardware, hardware related

        private AutoResetEvent _Signal_Command_Finished = new AutoResetEvent(false);
        private string[] _Received_Data = null;
        private String _Current_Command = String.Empty;
        private String _Current_Tag = string.Empty;
        private bool _CameraRequest_Result = false;
        private string _2DCode=string.Empty;
        #endregion

        public void RaiseEvent(string command, bool status, object result)
        {
            StationEventArgs arg = new StationEventArgs(hardwareName, command, status, result);
            eventClient.RaiseEvent(hardwareEvent, arg);
        }
    }
}
